package com.wili.c.asm;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import com.c.Ca;
import com.wili.c.Class9;
import com.wili.c.MiscFilter.ClsFilter;
import net.bytebuddy.jar.asm.Label;
import net.bytebuddy.jar.asm.MethodVisitor;
import net.bytebuddy.jar.asm.Type;
/**
 * Find in method...
 * @author weila 2021年2月25日
 */
class FunVisitor extends MethodVisitor {
	static final int UseLog = Asm9.FunVisitor_useLog;

	private AsmItems returnList;

	final ClsFilter clsFilter;

	AsmCont cont;
	public FunVisitor(MethodVisitor visit, ClsFilter filt, AsmCont cont) {
		super(Asm9.AsmVerion, visit);
		this.clsFilter = filt;
		this.cont = cont;
		this.returnList = cont.toList;
	}
	int lineNo;
	public void visitCode() {
		Ca.debug(UseLog, "M,visitCode:", ", lineNo=" + lineNo);
	}

	public void visitInsn(final int opcode) {
		Ca.debug(UseLog, "M,visitInsn:", ", lineNo=" + lineNo);
	}

	public void visitLdcInsn(final Object value) {
		//eg.类型字面值，如： int.class, ArrayList.class
		if (!(value instanceof Type))
			return;
		Class<?> cls = Asm9.asmType((Type) value);
		//Class<?> cls = Class9.forName(owner.replace("/", "."), -1);
		if (clsFilter != null && !clsFilter.accept(cls))
			return;
		returnList.adde(lineNo, cls);
		Ca.debug(UseLog, "M,visitLdcInsn:", ", lineNo=" + lineNo + "," + value);
	}

	@Override
	public void visitLineNumber(final int line, final Label start) {
		Ca.debug(UseLog, "M,lineNo=", lineNo);
		this.lineNo = line;
	}

	public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
		Ca.debug(UseLog, "M,visitLookupSwitchInsn:", ", lineNo=" + lineNo);
	}

	public void visitIntInsn(final int opcode, final int operand) {
		Ca.debug(UseLog, "M,visitIntInsn:", operand, ", lineNo=" + lineNo);
	}

	public void visitVarInsn(final int opcode, final int var) {
		Ca.debug(UseLog, "M,visitVarInsn:", var, ", lineNo=" + lineNo);
	}

	public void visitLabel(final Label label) {
		Ca.debug(UseLog, "M,visitLabel:", label, ", lineNo=" + lineNo);
	}

	public void visitJumpInsn(final int opcode, final Label label) {
		Ca.debug(UseLog, "M,visitJumpInsn:", "" + ", lineNo=" + lineNo);
	}

	public void visitParameter(final String name, final int access) {
		Ca.debug(UseLog, "M,visitParameter:", "" + name + ", lineNo=" + lineNo);
	}

	public void visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels) {
		super.visitTableSwitchInsn(min, max, dflt, labels);
		Ca.debug(UseLog, "M,visitTableSwitchInsn:", "" + ", lineNo=" + lineNo);
	}

	public void visitLocalVariable(final String name, final String descriptor, final String signature,
			final Label start, final Label end, final int index) {
		Ca.debug(UseLog, "M,visitLocalVariable:", name, ",lineNo=", lineNo);
		super.visitLocalVariable(name, descriptor, signature, start, end, index);
	}

	public void visitTypeInsn(int opcode, String type) {//类型
		Ca.debug(UseLog, "M,visitTypeInsn:", type + ", lineNo=" + lineNo);
		type = type.replace('/', '.');
		String cname = type;
		if (!type.contains(".")) {
			cname = net.bytebuddy.jar.asm.Type.getType(type).getClassName();
		}
		Class<?> cls = Class9.classOfName(cname, 1);
		if (cls == null)
			Ca.pause();
		if (cls.isArray()) {
			cls = Class9.bottomTypeOf(cls);
		}
		if (clsFilter != null && !clsFilter.accept(cls))
			return;
		returnList.adde(lineNo, cls);
	}

	@Override
	public void visitFieldInsn(final int opcode, final String owner, final String field, final String descriptor) {//属性
		Class<?> cls = Class9.forName(owner.replace("/", "."), -1);
		if (cls.isArray()) {
			cls = Class9.bottomTypeOf(cls);
		}
		if (UseLog == 1)
			Ca.warn(UseLog, opcode + ",M,visitFieldInsn :", cls.getName() + ".", field + ", lineNo=" + lineNo);
		if (cont.filt != null) {
			Field fd = Class9.findFieldUpwards(1, cls, field);
			Object owner2 = owner;
			if (!fd.getDeclaringClass().equals(cls)) {
				//asm 读 this.att时，把this当做本类的, 把super.name当做是父类的，两种写法的owner都不同，在此区分。
				owner2 = fd.getDeclaringClass();
			}
			cont.filt.doCode(opcode, owner2, field, lineNo);
			return;
		}
		if (field.equals("JarClassFilter"))
			Ca.pause();
		if (clsFilter != null && !clsFilter.accept(cls))
			return;
		Field fd = Class9.findFieldUpwards(1, cls, field);
		returnList.adde(lineNo, fd);
	}

	@Override
	public void visitMethodInsn(int opcode, String owner, String method, String descriptor, boolean isInterface) {//方法
		if (cont.filt != null) {
			cont.filt.doCode(opcode, owner, method, lineNo);
			return;
		}
		Class<?> cls = Class9.forName(owner.replace("/", "."), -1);

		Type[] types = net.bytebuddy.jar.asm.Type.getArgumentTypes(descriptor);
		Class<?>[] cc = Asm9.classesOfAsmTypes(types);
		if (clsFilter != null && !clsFilter.accept(cls))
			return;
		if (cls.isArray()) {//eg. cls is int[].class, method is clone()
			cls = Class9.bottomTypeOf(cls);
		}
		if (cls.equals(Thread.class))
			Ca.pause();
		if (clsFilter != null && !clsFilter.accept(cls))
			return;
		if (lineNo == 99)
			Ca.pause();
		Type[] types2 = net.bytebuddy.jar.asm.Type.getArgumentTypes(descriptor);
		Class<?>[] cc2 = Asm9.classesOfAsmTypes(types2);
		Executable methodRet = Asm9.methodOf(cls, method, cc2);
		Ca.debug(UseLog, "M,visitMethodInsn:", ",LN:", lineNo, "," + methodRet);
		if (methodRet == null) {
			return;
		}
		if (clsFilter != null && !clsFilter.accept(methodRet.getDeclaringClass()))
			return;
		returnList.adde(lineNo, methodRet);
	}
	static int inc;
}
